home *** CD-ROM | disk | FTP | other *** search
- #ifdef OS2
- char *ckzv = "OS/2 File support, 5A(074) 11 Jun 93";
- #else
- #ifdef aegis
- char *ckzv = "Aegis File support, 5A(074) 11 Jun 93";
- #else
- char *ckzv = "UNIX File support, 5A(074) 11 Jun 93";
- #endif /* aegis */
- #endif /* OS2 */
-
- /* C K U F I O -- Kermit file system support for UNIX, OS/2, and Aegis */
-
- /*
- Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
- Columbia University Academic Information Systems, New York City.
-
- Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
- York. The C-Kermit software may not be, in whole or in part, licensed or
- sold for profit as a software product itself, nor may it be included in or
- distributed with commercial products or otherwise distributed by commercial
- concerns to their clients or customers without written permission of the
- Office of Kermit Development and Distribution, Columbia University. This
- copyright notice must not be removed, altered, or obscured.
- */
-
- /* Include Files */
-
- #include "ckcdeb.h"
-
- #include <signal.h>
-
- #ifdef MINIX
- #include <limits.h>
- #endif /* MINIX */
- #ifdef POSIX
- #include <limits.h>
- #endif /* POSIX */
-
- /* Directory structure header file */
-
- #ifdef OS2
- /*
-
- C-Kermit's OS/2 support originally by Chris Adie <C.Adie@uk.ac.edinburgh>
- Edinburgh University Computing Service, Scotland, for C-Kermit 4F. Adapted
- to C-Kermit 5A and integrated into the UNIX support module by Kai Uwe Rommel
- <rommel@informatik.tu-muenchen.de>, Muenchen, Germany, December 1991.
- */
-
- /*
- Directory Separator macros, to allow this module to work with both UNIX and
- OS/2: Because of ambiguity with the command line editor escape \ character,
- the directory separator is currently left as / for OS/2 too, because the
- OS/2 kernel also accepts / as directory separator. But this is subject to
- change in future versions to conform to the normal OS/2 style.
- */
- #define DIRSEP '/'
- /* #define DIRSEP '\\' */
- #define ISDIRSEP(c) ((c)=='/'||(c)=='\\')
- #else /* not OS2 */
- #define DIRSEP '/'
- #define ISDIRSEP(c) ((c)=='/')
- #endif /* OS2 */
-
- #ifdef SDIRENT
- #define DIRENT
- #endif /* SDIRENT */
-
- #ifdef XNDIR
- #include <sys/ndir.h>
- #else /* !XNDIR */
- #ifdef NDIR
- #include <ndir.h>
- #else /* !NDIR, !XNDIR */
- #ifdef RTU
- #include "/usr/lib/ndir.h"
- #else /* !RTU, !NDIR, !XNDIR */
- #ifdef DIRENT
- #ifdef SDIRENT
- #include <sys/dirent.h>
- #else
- #include <dirent.h>
- #endif /* SDIRENT */
- #else
- #ifdef OS2
- #define OPENDIR
- #define DIRENT
- #include "ckodir.h"
- #else/* !RTU, !NDIR, !XNDIR, !DIRENT, !OS2, i.e. all others */
- #include <sys/dir.h>
- #endif /* OS2 */
- #endif /* DIRENT */
- #endif /* RTU */
- #endif /* NDIR */
- #endif /* XNDIR */
-
- #ifdef OS2 /* OS/2 file system interface */
- #define BSD4 /* is like Berkeley UNIX */
- #define NOFILEH /* with no <file.h> */
- #include <sys/utime.h>
- #include <stdlib.h>
- #include <process.h>
- extern int binary; /* We need to know this for open() */
- #ifdef __IBMC__
- extern FILE *popen(char *, char *);
- extern int pclose(FILE *);
- #else
- #ifndef __EMX__
- #define popen _popen
- #define pclose _pclose
- #include <share.h>
- #define fopen(n, m) _fsopen(n, m, SH_DENYWR)
- #endif /* __EMX__ */
- #endif /* __IBMC__ */
- #else
- #include <pwd.h> /* Password file for shell name */
- #endif /* OS2 */
-
- #ifndef OS2
- #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
- #include <sys/utime.h> /* for extra fields required by */
- #endif /* SYSUTIMEH */ /* 88Open spec. */
- #endif /* OS2 */
-
- #ifdef POSIX
- #define TIMESTAMP
- #define SYSUTIMEH
- #include <utime.h>
- #endif /* POSIX */
-
- #ifdef BSD44 /* BSD 4.4 */
- #define TIMESTAMP /* Can do file dates */
- #include <sys/time.h>
- #include <sys/timeb.h>
-
- #else
-
- #ifdef BSD4 /* BSD 4.3 and below */
- #define TIMESTAMP /* Can do file dates */
- #include <time.h> /* Need this */
- #include <sys/timeb.h> /* Need this if really BSD */
-
- #else
-
- #ifdef SVORPOSIX
- #ifndef TIMESTAMP
- #define TIMESTAMP
- #endif /* TIMESTAMP */
- #include <time.h>
-
- /* void tzset(); (the "void" type upsets some compilers) */
- #ifndef ultrix
- #ifndef CONVEX9
- /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
- extern long timezone;
- #endif /* CONVEX9 */
- #endif /* ultrix */
- #endif /* SVORPOSIX */
- #endif /* BSD4 */
- #endif /* BSD44 */
-
- /* Is `y' a leap year? */
- #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
-
- /* Number of leap years from 1970 to `y' (not including `y' itself). */
- #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
-
- #ifdef COMMENT /* not used */
- /* Number of days in each month of the year. */
- static char monlens[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- #endif /* COMMENT */
-
- #ifdef CIE
- #include <stat.h> /* File status */
- #else
- #include <sys/stat.h>
-
- #ifdef OS2
- #include <sys/types.h>
- /* because standard stat has trouble with trailing /'s we have to wrap it */
- int os2stat(char *, struct stat *);
- #ifdef __IBMC__
- #ifdef system
- #undef system
- #endif
- #ifdef stat
- #undef stat
- #define __IBMC__STAT
- #endif
- #endif
- #define stat(path, buf) os2stat(path, buf)
- #endif /* OS2 */
- #endif /* CIE */
-
- /*
- Functions (n is one of the predefined file numbers from ckcker.h):
-
- zopeni(n,name) -- Opens an existing file for input.
- zopeno(n,name,attr,fcb) -- Opens a new file for output.
- zclose(n) -- Closes a file.
- zchin(n,&c) -- Gets the next character from an input file.
- zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
- zsout(n,s) -- Write a null-terminated string to output file, buffered.
- zsoutl(n,s) -- Like zsout, but appends a line terminator.
- zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
- zchout(n,c) -- Add a character to an output file, unbuffered.
- zchki(name) -- Check if named file exists and is readable, return size.
- zchko(name) -- Check if named file can be created.
- zchkspa(name,n) -- Check if n bytes available to create new file, name.
- znewn(name,s) -- Make a new unique file name based on the given name.
- zdelet(name) -- Delete the named file.
- zxpand(string) -- Expands the given wildcard string into a list of files.
- znext(string) -- Returns the next file from the list in "string".
- zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
- zclosf() -- Close input file associated with zxcmd()'s lower fork.
- zrtol(n1,n2) -- Convert remote filename into local form.
- zltor(n1,n2) -- Convert local filename into remote form.
- zchdir(dirnam) -- Change working directory.
- zhome() -- Return pointer to home directory name string.
- zkself() -- Kill self, log out own job.
- zsattr(struct zattr *) -- Return attributes for file which is being sent.
- zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
- zrename(old, new) -- Rename a file.
- */
-
- /* Kermit-specific includes */
- /*
- Definitions here supersede those from system include files.
- ckcdeb.h is included above.
- */
- #include "ckcker.h" /* Kermit definitions */
- #include "ckucmd.h" /* For sys-dependent keyword tables */
- #include "ckuver.h" /* Version herald */
-
- char *ckzsys = HERALD;
-
- /*
- File access checking ... There are two calls to access() in this module.
- If this program is installed setuid or setgid on a Berkeley-based UNIX
- system that does NOT incorporate the saved-original-effective-uid/gid
- feature, then, when we have swapped the effective and original uid/gid,
- access() fails because it uses what it thinks are the REAL ids, but we have
- swapped them. This occurs on systems where ANYBSD is defined, NOSETREU
- is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take
- care of this situation like so:
-
- ifdef ANYBSD
- ifndef NOSETREU
- ifndef SAVEDUID
- define SW_ACC_ID
- endif
- endif
- endif
-
- But we can't test such a general scheme everywhere, so let's only do this
- when we know we have to...
- */
- #ifdef NEXT /* NeXTSTEP 1.0-3.0 */
- #define SW_ACC_ID
- #endif /* NEXT */
-
- /* Support for tilde-expansion in file and directory names */
-
- #ifdef POSIX
- #define NAMEENV "LOGNAME"
- #endif /* POSIX */
-
- #ifdef BSD4
- #define NAMEENV "USER"
- #endif /* BSD4 */
-
- #ifdef ATTSV
- #define NAMEENV "LOGNAME"
- #endif /* ATTSV */
-
- /* Berkeley Unix Version 4.x */
- /* 4.1bsd support from Charles E Brooks, EDN-VAX */
-
- #ifdef BSD4
- #ifdef MAXNAMLEN
- #define BSD42
- #endif /* MAXNAMLEN */
- #endif /* BSD4 */
-
- /* Definitions of some system commands */
-
- #ifdef OS2
- char *DELCMD = "del "; /* For file deletion */
- char *PWDCMD = "chdir "; /* For saying where I am */
- char *TYPCMD = "type "; /* For typing a file */
- char *DIRCMD = "dir "; /* For directory listing */
- char *DIRCM2 = "dir "; /* For directory listing, no args */
- char *WHOCMD = ""; /* Who's there? */
- char *SPACMD = "dir | find \"bytes free\""; /* For space on disk */
- char *SPACM2 = "dir | find \"bytes free\""; /* For space on disk */
-
- #else /* Not OS2, ergo UNIX */
-
- char *DELCMD = "rm -f "; /* For file deletion */
- char *PWDCMD = "pwd "; /* For saying where I am */
- #ifdef COMMENT
- char *DIRCMD = "/bin/ls -ld "; /* For directory listing */
- char *DIRCM2 = "/bin/ls -ld *"; /* For directory listing, no args */
- #else
- char *DIRCMD = "/bin/ls -l "; /* For directory listing */
- char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */
- #endif /* COMMENT */
- char *TYPCMD = "cat "; /* For typing a file */
-
- #ifdef FT18 /* Fortune For:Pro 1.8 */
- #undef BSD4
- #endif /* FT18 */
-
- #ifdef BSD4
- char *SPACMD = "pwd ; df ."; /* Space in current directory */
- #else
- #ifdef FT18
- char *SPACMD = "pwd ; du ; df .";
- #else
- char *SPACMD = "df ";
- #endif /* FT18 */
- #endif /* BSD4 */
-
- char *SPACM2 = "df "; /* For space in specified directory */
-
- #ifdef FT18
- #define BSD4
- #endif /* FT18 */
-
- #ifdef BSD4
- char *WHOCMD = "finger ";
- #else
- char *WHOCMD = "who ";
- #endif /* BSD4 */
-
- #endif /* OS2 */
-
- #ifdef DTILDE /* For tilde expansion */
- _PROTOTYP( char * tilde_expand, (char *) );
- #endif /* DTILDE */
-
- /* More system-dependent includes, which depend on symbols defined */
- /* in the Kermit-specific includes. Oh what a tangled web we weave... */
-
- #ifdef COHERENT /* <sys/file.h> */
- #define NOFILEH
- #endif /* COHERENT */
-
- #ifdef MINIX
- #define NOFILEH
- #endif /* MINIX */
-
- #ifdef aegis
- #define NOFILEH
- #endif /* aegis */
-
- #ifdef unos
- #define NOFILEH
- #endif /* unos */
-
- #ifndef NOFILEH
- #include <sys/file.h>
- #endif /* NOFILEH */
-
- #ifndef is68k /* Whether to include <fcntl.h> */
- #ifndef BSD41 /* All but a couple UNIXes have it. */
- #ifndef FT18
- #ifndef COHERENT
- #include <fcntl.h>
- #endif /* COHERENT */
- #endif /* FT18 */
- #endif /* BSD41 */
- #endif /* not is68k */
-
- #ifdef COHERENT
- #ifdef _I386
- #include <fcntl.h>
- #else
- #include <sys/fcntl.h>
- #endif /* _I386 */
- #endif /* COHERENT */
-
- /*
- Change argument to "(const char *)" if this causes trouble.
- Or... if it causes trouble, then maybe it was already declared
- in a header file after all, so you can remove this prototype.
- */
- #ifndef _POSIX_SOURCE
- #ifndef NEXT
- #ifndef SVR4
- /* POSIX <pwd.h> already gave prototypes for these. */
- #ifdef IRIX40
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- _PROTOTYP( struct passwd * getpwnam, (char *) );
- #endif /* IRIX40 */
- #ifndef SUNOS4
- _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
- #endif /* SUNOS4 */
- _PROTOTYP( struct passwd * getpwent, (void) );
- #endif /* SVR4 */
- #endif /* NEXT */
- #endif /* _POSIX_SOURCE */
-
- /* Define macros for getting file type */
-
- #ifdef OXOS
- /*
- Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
- incorrectly, so we force their redefinition.
- */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* OXOS */
-
- #ifdef UTSV /* Same deal for Amdahl UTSV */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* UTSV */
-
- #ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* UNISYS52 */
-
- #ifndef S_ISREG
- #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
- #endif /* S_ISREG */
- #ifndef S_ISDIR
- #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
- #endif /* S_ISDIR */
-
- /* Define maximum length for a file name if not already defined */
-
- #ifndef MAXNAMLEN
- #ifdef sun
- #define MAXNAMLEN 255
- #else
- #ifdef FILENAME_MAX
- #define MAXNAMLEN FILENAME_MAX
- #else
- #ifdef NAME_MAX
- #define MAXNAMLEN NAME_MAX
- #else
- #ifdef _POSIX_NAME_MAX
- #define MAXNAMLEN _POSIX_NAME_MAX
- #else
- #ifdef _D_NAME_MAX
- #define MAXNAMLEN _D_NAME_MAX
- #else
- #ifdef DIRSIZ
- #define MAXNAMLEN DIRSIZ
- #else
- #define MAXNAMLEN 14
- #endif /* DIRSIZ */
- #endif /* _D_NAME_MAX */
- #endif /* _POSIX_NAME_MAX */
- #endif /* NAME_MAX */
- #endif /* FILENAME_MAX */
- #endif /* sun */
- #endif /* MAXNAMLEN */
-
- /* Longest pathname */
-
- #ifdef MAXPATHLEN
- #ifdef MAXPATH
- #undef MAXPATH
- #endif /* MAXPATH */
- #define MAXPATH MAXPATHLEN
- #else
- #ifdef PATH_MAX
- #define MAXPATH PATH_MAX
- #else
- #ifdef _POSIX_PATH_MAX
- #define MAXPATH _POSIX_PATH_MAX
- #else
- #ifdef BSD42
- #define MAXPATH 1024
- #else
- #define MAXPATH 255
- #endif /* BSD42 */
- #endif /* _POSIX_PATH_MAX */
- #endif /* PATH_MAX */
- #endif /* MAXPATHLEN */
-
- /* Maximum number of filenames for wildcard expansion */
-
- #ifdef PROVX1
- #define MAXWLD 50
- #else
- #ifdef BSD29
- #define MAXWLD 50
- #else
- #ifdef pdp11
- #define MAXWLD 50
- #else
- #define MAXWLD 1000
- #endif /* pdp11 */
- #endif /* BSD29 */
- #endif /* PROVX1 */
-
- /* More internal function prototypes */
- /*
- * The path structure is used to represent the name to match.
- * Each slash-separated segment of the name is kept in one
- * such structure, and they are linked together, to make
- * traversing the name easier.
- */
- struct path {
- char npart[MAXNAMLEN+4]; /* name part of path segment */
- struct path *fwd; /* forward ptr */
- };
- _PROTOTYP( int shxpand, (char *, char *[], int ) );
- _PROTOTYP( static int fgen, (char *, char *[], int ) );
- _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
- _PROTOTYP( static VOID addresult, (char *) );
- _PROTOTYP( static int match, (char *, char *) );
- _PROTOTYP( static char * whoami, (void) );
- _PROTOTYP( char * xindex, (char *, char) );
- _PROTOTYP( UID_T real_uid, (void) );
- _PROTOTYP( struct path *splitpath, (char *p) );
-
- /* Some systems define these symbols in include files, others don't... */
-
- #ifndef R_OK
- #define R_OK 4 /* For access */
- #endif
-
- #ifndef W_OK
- #define W_OK 2
- #endif
-
- #ifndef O_RDONLY
- #define O_RDONLY 000
- #endif
-
- /* Declarations */
-
- int maxnam = MAXNAMLEN; /* Available to the outside */
- int maxpath = MAXPATH;
-
- FILE *fp[ZNFILS] = { /* File pointers */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL };
- #ifdef OS2
- int ispipe[ZNFILS]; /* Flag for file is a pipe */
- #endif /* OS2 */
-
- /* Buffers and pointers used in buffered file input and output. */
- #ifdef DYNAMIC
- extern char *zinbuffer, *zoutbuffer;
- #else
- extern char zinbuffer[], zoutbuffer[];
- #endif /* DYNAMIC */
- extern char *zinptr, *zoutptr;
- extern int zincnt, zoutcnt;
- extern int wildxpand;
-
- extern UID_T real_uid();
-
- static long iflen = -1L; /* Input file length */
-
- static PID_T pid = 0; /* pid of child fork */
- static int fcount; /* Number of files in wild group */
- static char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
- #ifndef NOFRILLS
- static char zmbuf[200]; /* For mail, remote print strings */
- #endif /* NOFRILLS */
-
- /* static */ /* Not static, must be global now. */
- char *mtchs[MAXWLD], /* Matches found for filename */
- **mtchptr; /* Pointer to current match */
-
- /* Z K S E L F -- Kill Self: log out own job, if possible. */
-
- /* Note, should get current pid, but if your system doesn't have */
- /* getppid(), then just kill(0,9)... */
-
- #ifndef SVR3
- #ifndef POSIX
- #ifndef OSFPC
- /* Already declared in unistd.h for SVR3 and POSIX */
- #ifdef CK_ANSIC
- extern PID_T getppid(void);
- #else
- #ifndef PS2AIX10
- extern PID_T getppid();
- #endif /* PS2AIX10 */
- #endif /* CK_ANSIC */
- #endif /* OSFPC */
- #endif /* POSIX */
- #endif /* SVR3 */
- int
- zkself() { /* For "bye", but no guarantee! */
- #ifdef PROVX1
- return(kill(0,9));
- #else
- #ifdef V7
- return(kill(0,9));
- #else
- #ifdef TOWER1
- return(kill(0,9));
- #else
- #ifdef FT18
- return(kill(0,9));
- #else
- #ifdef aegis
- return(kill(0,9));
- #else
- #ifdef COHERENT
- return(kill((PID_T)getpid(),1));
- #else
- #ifdef OS2
- exit(3);
- #else
- #ifdef PID_T
- exit(kill((PID_T)getppid(),1));
- #else
- exit(kill(getppid(),1));
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
- }
-
- /* Z O P E N I -- Open an existing file for input. */
-
- int
- zopeni(n,name) int n; char *name; {
- debug(F111," zopeni",name,n);
- debug(F101," fp","", fp[n]);
- if (chkfn(n) != 0) return(0);
- zincnt = 0; /* Reset input buffer */
- if (n == ZSYSFN) { /* Input from a system function? */
- /*** Note, this function should not be called with ZSYSFN ***/
- /*** Always call zxcmd() directly, and give it the real file number ***/
- /*** you want to use. ***/
- debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
- *nambuf = '\0'; /* No filename. */
- return(0); /* fail. */
- #ifdef COMMENT
- return(zxcmd(n,name)); /* Try to fork the command */
- #endif
- }
- if (n == ZSTDIO) { /* Standard input? */
- if (isatty(0)) {
- fprintf(stderr,"Terminal input not allowed");
- debug(F110,"zopeni: attempts input from unredirected stdin","",0);
- return(0);
- }
- fp[ZIFILE] = stdin;
- #ifdef OS2
- setmode(fileno(stdin),O_BINARY);
- #endif /* OS2 */
- return(1);
- }
- #ifdef OS2
- if (n == ZIFILE || n == ZRFILE)
- fp[n] = fopen(name,"rb"); /* Binary mode */
- else
- #endif /* OS2 */
- fp[n] = fopen(name,"r"); /* Real file, open it. */
- debug(F111," zopeni", name, fp[n]);
- if (fp[n] == NULL) perror("zopeni");
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z O P E N O -- Open a new file for output. */
-
- int
- zopeno(n,name,zz,fcb)
- /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
-
- char p[8]; /* (===OS2 change===) */
-
- /* As of Version 5A, the attribute structure and the file information */
- /* structure are included in the arglist. */
-
- #ifdef DEBUG
- debug(F111,"zopeno",name,n);
- if (fcb) {
- debug(F101,"zopeno fcb disp","",fcb->dsp);
- debug(F101,"zopeno fcb type","",fcb->typ);
- debug(F101,"zopeno fcb char","",fcb->cs);
- } else {
- debug(F100,"zopeno fcb is NULL","",0);
- }
- if (n != ZDFILE)
- debug(F111," zopeno",name,n);
- #endif /* DEBUG */
- if (chkfn(n) != 0) return(0);
- if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
- fp[ZOFILE] = stdout;
- #ifdef DEBUG
- if (n != ZDFILE)
- debug(F101," fp[]=stdout", "", fp[n]);
- #endif /* DEBUG */
- zoutcnt = 0;
- zoutptr = zoutbuffer;
- return(1);
- }
-
- /* A real file. Open it in desired mode (create or append). */
-
- strcpy(p,"w"); /* Assume write/create mode */
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) /* Does it say Append? */
- strcpy(p,"a"); /* Yes. */
- }
- #ifdef OS2
- if (n == ZOFILE || n == ZSFILE) /* OS/2 binary mode */
- strcat(p,"b");
- #endif /* OS2 */
- fp[n] = fopen(name,p); /* Try to open the file */
-
- if (fp[n] == NULL) { /* Failed */
- debug(F101,"zopeno failed errno","",errno);
- #ifdef COMMENT /* Let upper levels print message. */
- perror("Can't open output file");
- #endif /* COMMENT */
- } else { /* Succeeded */
- if (n == ZDFILE) /* If it's the debug log */
- setbuf(fp[n],NULL); /* make it unbuffered */
- else
- debug(F100, "zopeno ok", "", 0);
- }
- zoutcnt = 0; /* (PWP) reset output buffer */
- zoutptr = zoutbuffer;
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z C L O S E -- Close the given file. */
-
- /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
-
- int
- zclose(n) int n; {
- int x, x2;
- if (chkfn(n) < 1) return(0); /* Check range of n */
-
- if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
- x2 = zoutdump();
- else
- x2 = 0;
-
- x = 0; /* Initialize return code */
- if (fp[ZSYSFN]) { /* If file is really pipe */
- x = zclosf(n); /* do it specially */
- } else {
- if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
- fp[n] = NULL;
- }
- iflen = -1L; /* Invalidate file length */
- if (x == EOF) /* if we got a close error */
- return(-1);
- else if (x2 < 0) /* or an error flushing the last buffer */
- return(-1); /* then return an error */
- else
- return(1);
- }
-
- /* Z C H I N -- Get a character from the input file. */
-
- /* Returns -1 if EOF, 0 otherwise with character returned in argument */
-
- int
- zchin(n,c) int n; int *c; {
- int a, x;
-
- /* (PWP) Just in case this gets called when it shouldn't. */
- if (n == ZIFILE) {
- x = zminchar();
- *c = x;
- return(x);
- }
- /* if (chkfn(n) < 1) return(-1); */
- a = getc(fp[n]);
- if (a == EOF) return(-1);
- #ifdef OS2
- if (!binary && a == 0x1A) /* Ctrl-Z marks EOF for text mode*/
- return(-1);
- #endif
- *c = (CHAR) a & 0377;
- return(0);
- }
-
- /* Z S I N L -- Read a line from a file */
-
- /*
- Writes the line into the address provided by the caller.
- n is the Kermit "channel number".
- Writing terminates when newline is encountered, newline is not copied.
- Writing also terminates upon EOF or if length x is exhausted.
- Returns 0 on success, -1 on EOF or error.
- */
- int
- zsinl(n,s,x) int n, x; char *s; {
- int a, z = 0; /* z is return code. */
-
- if (chkfn(n) < 1) { /* Make sure file is open */
- return(-1);
- }
- a = -1; /* Current character, none yet. */
- while (x--) { /* Up to given length */
- #ifndef NLCHAR
- int old;
- old = a; /* Previous character */
- #endif
- if (zchin(n,&a) < 0) { /* Read a character from the file */
- debug(F101,"zsinl","",a);
- z = -1; /* EOF or other error */
- break;
- }
- #ifdef NLCHAR
- if (a == (char) NLCHAR) break; /* Single-character line terminator */
- #else /* CRLF line terminator */
- if (a == '\015') continue; /* CR, get next character */
- if (old == '\015') { /* Previous character was CR */
- if (a == '\012') break; /* This one is LF, so we have a line */
- else *s++ = '\015'; /* Not LF, deposit CR */
- }
- #ifdef OS2
- /*
- I'm not sure I understand this one, so let's keep it only for OS/2 for now.
- */
- if (a == '\012') break; /* Break on single LF too */
- #endif /* OS2 */
- #endif /* NLCHAR */
- *s = a; /* Deposit character */
- s++;
- }
- *s = '\0'; /* Terminate the string */
- return(z);
- }
-
- /*
- * (PWP) (re)fill the buffered input buffer with data. All file input
- * should go through this routine, usually by calling the zminchar()
- * macro (in ckcker.h).
- */
-
- /*
- * Suggestion: if fread() returns 0, call ferror to find out what the
- * problem was. If it was not EOF, then return -2 instead of -1.
- * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
- * if it gets -2 return from zminchar macro.
- */
- int
- zinfill() {
- int x;
-
- errno = 0;
- zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
- #ifdef COMMENT
- debug(F101,"zinfill fp","",fp[ZIFILE]);
- debug(F101,"zinfill zincnt","",zincnt);
- #endif
- if (zincnt == 0) {
- #ifndef UTEK
- #ifdef ferror
- x = ferror(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill ferror","",x);
- if (x) return(-2);
- #endif /* ferror */
- #else
- x = feof(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill feof","",x);
- if (!x && ferror(fp[ZIFILE])) return(-2);
- #endif /* UTEK */
- return(-1);
- }
- zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
- zincnt--; /* one less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
-
- /* Z S O U T -- Write a string out to the given file, buffered. */
-
- int
- zsout(n,s) int n; char *s; {
- if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
- #ifndef OS2
- if (n == ZSFILE)
- return(write(fileno(fp[n]),s,(int)strlen(s)));
- else
- #endif /* OS2 */
- return(fputs(s,fp[n]) == EOF ? -1 : 0);
- }
-
- /* Z S O U T L -- Write string to file, with line terminator, buffered */
-
- int
- zsoutl(n,s) int n; char *s; {
- /* if (chkfn(n) < 1) return(-1); */
- if (fputs(s,fp[n]) == EOF) return(-1);
- if (fputs("\n",fp[n]) == EOF) return(-1); /* (===OS2 ? \r\n) */
- return(0);
- }
-
- /* Z S O U T X -- Write x characters to file, unbuffered. */
-
- int
- zsoutx(n,s,x) int n, x; char *s; {
- #ifdef COMMENT
- if (chkfn(n) < 1) return(-1);
- return(write(fp[n]->_file,s,x));
- #endif
- return(write(fileno(fp[n]),s,x) == x ? x : -1);
- }
-
-
- /* Z C H O U T -- Add a character to the given file. */
-
- /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
-
- int
- #ifdef CK_ANSIC
- zchout(register int n, char c)
- #else
- zchout(n,c) register int n; char c;
- #endif /* CK_ANSIC */
- /* zchout() */ {
- /* if (chkfn(n) < 1) return(-1); */
- #ifndef OS2
- if (n == ZSFILE) { /* Use unbuffered for session log */
- return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
- } else { /* Buffered for everything else */
- #endif /* OS2 */
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- #ifndef OS2
- }
- #endif /* OS2 */
- }
-
- /* (PWP) buffered character output routine to speed up file IO */
-
- int
- zoutdump() {
- int x;
- zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
- debug(F101,"zoutdump chars","",zoutcnt);
- if (zoutcnt == 0) { /* Nothing to output */
- return(0);
- } else if (zoutcnt < 0) { /* Unexpected negative argument */
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* and fail. */
- }
-
- /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
- /* followed by a write() would improve the efficiency, especially when */
- /* writing to stdout. Subsequent tests showed a 5-fold improvement! */
- /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */
-
- fflush(fp[ZOFILE]);
- if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
- debug(F101,"zoutdump write ok","",zoutcnt);
- zoutcnt = 0; /* Reset output buffer count */
- return(0); /* write() worked OK */
- } else {
- debug(F101,"zoutdump write error","",errno);
- debug(F101,"zoutdump write returns","",x);
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* write() failed */
- }
- }
-
- /* C H K F N -- Internal function to verify file number is ok */
-
- /*
- Returns:
- -1: File number n is out of range
- 0: n is in range, but file is not open
- 1: n in range and file is open
- */
- int
- chkfn(n) int n; {
- #ifdef COMMENT /* Save some stack space */
- switch (n) {
- case ZCTERM:
- case ZSTDIO:
- case ZIFILE:
- case ZOFILE:
- case ZDFILE:
- case ZTFILE:
- case ZPFILE:
- case ZSFILE:
- case ZSYSFN:
- case ZRFILE:
- case ZWFILE: break;
- default:
- debug(F101,"chkfn: file number out of range","",n);
- fprintf(stderr,"?File number out of range - %d\n",n);
- return(-1);
- }
- return( (fp[n] == NULL) ? 0 : 1 );
- #else
- if (n < 0 || n >= ZNFILS)
- return(-1);
- else return( (fp[n] == NULL) ? 0 : 1 );
- #endif /* COMMENT */
- }
-
- /* Z C H K I -- Check if input file exists and is readable */
-
- /*
- Returns:
- >= 0 if the file can be read (returns the size).
- -1 if file doesn't exist or can't be accessed,
- -2 if file exists but is not readable (e.g. a directory file).
- -3 if file exists but protected against read access.
- */
- /*
- For Berkeley Unix, a file must be of type "regular" to be readable.
- Directory files, special files, and symbolic links are not readable.
- */
- long
- zchki(name) char *name; {
- struct stat buf;
- int x;
-
- #ifdef UNIX
- x = strlen(name);
- if (x == 9 && !strcmp(name,"/dev/null"))
- return(0);
- #endif /* UNIX */
-
- x = stat(name,&buf);
- if (x < 0) {
- debug(F111,"zchki stat fails",name,errno);
- return(-1);
- }
- if (!S_ISREG (buf.st_mode)) { /* Must be regular file */
- debug(F111,"zchki skipping:",name,x);
- return(-2);
- }
- debug(F111,"zchki stat ok:",name,x);
-
- #ifdef SW_ACC_ID
- debug(F100,"zchki swapping ids for access()","",0);
- priv_on();
- #endif /* SW_ACC_ID */
- x = access(name,R_OK);
- #ifdef SW_ACC_ID
- priv_off();
- debug(F100,"zchki swapped ids restored","",0);
- #endif /* SW_ACC_ID */
- if (x < 0) { /* Is the file accessible? */
- debug(F111," access failed:",name,x); /* No */
- return(-3);
- } else {
- iflen = buf.st_size; /* Yes, remember size */
- strncpy(nambuf,name,MAXNAMLEN); /* and name globally. */
- debug(F111," access ok:",name,(int) iflen);
- return( (iflen > -1L) ? iflen : 0L );
- }
- }
-
- /* Z C H K O -- Check if output file can be created */
-
- /*
- Returns -1 if write permission for the file would be denied, 0 otherwise.
- */
- int
- zchko(name) char *name; {
- int i, x;
- char *s;
-
- if (!name) return(-1); /* Watch out for null pointer. */
- x = (int)strlen(name); /* Get length of filename */
- debug(F101," length","",x);
-
- #ifdef UNIX
- /*
- Writing to null device is OK.
- */
- if (x == 9 && !strcmp(name,"/dev/null"))
- return(0);
- #endif /* UNIX */
-
- s = malloc(x+3); /* Must copy because we can't */
- if (!s) { /* write into our argument. */
- fprintf(stderr,"Malloc error 46\n");
- return(-1);
- }
- strcpy(s,name);
-
- for (i = x; i > 0; i--) /* Strip filename from right. */
- if (ISDIRSEP(s[i-1])) break;
- debug(F101," i","",i);
-
- #ifdef COMMENT
- /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
- if (i == 0) /* If no path, use current directory */
- strcpy(s,"./");
- else /* Otherwise, use given one. */
- s[i] = '\0';
- #else
- /* So now we use "path/." if path given, or "." if no path given. */
- s[i++] = '.'; /* Append "." to path. */
- s[i] = '\0';
- #endif /* COMMENT */
-
- #ifdef SW_ACC_ID
- debug(F100,"zchko swapping ids for access()","",0);
- priv_on();
- #endif /* SW_ACC_ID */
- #ifdef OS2 /* No unwritable directories in OS/2 */
- x = 0;
- #else
- x = access(s,W_OK); /* Check access of path. */
- #endif /* OS2 */
- #ifdef SW_ACC_ID
- priv_off();
- debug(F100,"zchko swapped ids restored","",0);
- #endif /* SW_ACC_ID */
- if (x < 0)
- debug(F111,"zchko access failed:",s,errno);
- else
- debug(F111,"zchko access ok:",s,x);
- free(s); /* Free temporary storage */
- return((x < 0) ? -1 : 0); /* and return. */
- }
-
- /* Z D E L E T -- Delete the named file. */
-
- int
- zdelet(name) char *name; {
- return(unlink(name));
- }
-
-
- /* Z R T O L -- Convert remote filename into local form */
-
- /* For UNIX, this means changing uppercase letters to lowercase. */
-
- VOID
- zrtol(name,name2) char *name, *name2; {
- char *p; int flag = 0;
- if (!name || !name2) return;
- debug(F101,"zrtol original name","",name);
- p = name2;
- for ( ; *name != '\0'; name++) {
- if (*name > ' ') flag = 1; /* Strip leading blanks and controls */
- if (flag == 0 && *name < '!') continue;
- *p++ = isupper(*name) ? tolower(*name) : *name;
- }
- *p-- = '\0'; /* Terminate */
- while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
- *p-- = '\0';
- if (*name2 == '\0') strcpy(name2,"NONAME");
- #ifdef OS2
- if (!IsFileNameValid(name2))
- ChangeNameForFAT(name2);
- #endif /* OS2 */
- debug(F110,"zrtol new name",name2,0);
- }
-
-
- /* Z S T R I P -- Strip device & directory name from file specification */
-
- /* Strip pathname from filename "name", return pointer to result in name2 */
-
- #ifdef pdp11
- static char work[100]; /* buffer for use by zstrip and zltor */
- #else
- static char work[257];
- #endif /* pdp11 */
-
- VOID
- zstrip(name,name2) char *name, **name2; {
- char *cp, *pp;
- debug(F110,"zstrip before",name,0);
- pp = work;
- #ifdef DTILDE
- if (*name == '~') name++;
- #endif /* DTILDE */
- for (cp = name; *cp != '\0'; cp++) {
- if (ISDIRSEP(*cp))
- pp = work;
- else
- *pp++ = *cp;
- }
- *pp = '\0'; /* Terminate the string */
- *name2 = work;
- debug(F110,"zstrip after",*name2,0);
- }
-
- /* Z L T O R -- Local TO Remote */
-
- VOID
- zltor(name,name2) char *name, *name2; {
- char *cp, *pp;
- int dc = 0;
- #ifdef aegis
- char *namechars;
- int tilde = 0, bslash = 0;
-
- if ((namechars = getenv("NAMECHARS")) != NULL) {
- if (xindex(namechars, '~' ) != NULL) tilde = '~';
- if (xindex(namechars, '\\') != NULL) bslash = '\\';
- } else {
- tilde = '~';
- bslash = '\\';
- }
- #endif /* aegis */
-
- debug(F110,"zltor",name,0);
- pp = work;
- #ifdef aegis
- cp = name;
- if (tilde && *cp == tilde)
- ++cp;
- for (; *cp != '\0'; cp++) {
- if (*cp == '/' || *cp == bslash) { /* strip path name */
- #else
- for (cp = name; *cp != '\0'; cp++) { /* strip path name */
- if (ISDIRSEP(*cp)) {
- #endif /* aegis */
- dc = 0;
- pp = work;
- }
- else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
- else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */
- else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */
- else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
- else *pp++ = *cp;
- }
- *pp = '\0'; /* Tie it off. */
- cp = name2; /* If nothing before dot, */
- if (*work == '.') *cp++ = 'X'; /* insert 'X' */
- strcpy(cp,work);
- debug(F110," name2",name2,0);
- }
-
-
- /* Z C H D I R -- Change directory */
- /*
- Call with:
- dirnam = pointer to name of directory to change to,
- which may be "" or NULL to indicate user's home directory.
- Returns:
- 0 on failure
- 1 on success
- */
- int
- zchdir(dirnam) char *dirnam; {
- char *hd, *sp, *p;
-
- debug(F110,"zchdir",dirnam,0);
- if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
- dirnam = zhome(); /* use user's home directory. */
- sp = dirnam;
- debug(F110,"zchdir 2",dirnam,0);
-
- #ifdef DTILDE
- hd = tilde_expand(dirnam); /* Attempt to expand tilde */
- if (*hd == '\0') hd = dirnam; /* in directory name. */
- #else
- hd = dirnam;
- #endif /* DTILDE */
- debug(F110,"zchdir 3",hd,0);
- #ifdef pdp11
- /* Just to save some space */
- return((chdir(hd) == 0) ? 1 : 0);
- #else
- #ifdef OS2
- if (isalpha(hd[0]) && hd[1] == ':') {
- if (zchdsk(hd[0]))
- return(0);
- if (hd[2] == 0)
- return(1); /* Handle drive-only case */
- }
- #endif /* OS2 */
- if (chdir(hd) == 0) return(1); /* Try to cd */ /* (===OS2===) */
- p = sp; /* Failed, lowercase it. */
- while (*p) {
- if (isupper(*p)) *p = tolower(*p);
- p++;
- }
- debug(F110,"zchdir 4",hd,0);
- #ifdef DTILDE
- hd = tilde_expand(sp); /* Try again to expand tilde */
- if (*hd == '\0') hd = sp;
- #else
- hd = sp; /* Point to result */
- #endif /* DTILDE */
- debug(F110,"zchdir 5",hd,0);
- return((chdir(hd) == 0) ? 1 : 0);
- #endif /* pdp11 */
- }
-
- /* Z H O M E -- Return pointer to user's home directory */
-
- char *
- zhome() {
- char *home = getenv("HOME");
- #ifdef OS2
- extern char startupdir[];
- return(home ? home : startupdir);
- #else
- return(home ? home : ".");
- #endif
- }
-
- /* Z G T D I R -- Return pointer to user's current directory */
-
- #ifdef pdp11
- #define CWDBL 80 /* Save every byte we can... */
- #else
- #ifdef MAXPATHLEN
- #define CWDBL MAXPATHLEN
- #else
- #define CWDBL 100
- #endif /* MAXPATHLEN */
- #endif /* pdp11 */
- static char cwdbuf[CWDBL+1];
-
- char *
- zgtdir() {
- char *buf;
-
- #ifdef BSD44
- extern char *getwd();
- buf = cwdbuf;
- return(getwd(buf));
- #else
- #ifdef SVORPOSIX
- extern char *getcwd();
- buf = cwdbuf;
- return(getcwd(buf,CWDBL));
- #else
- #ifdef COHERENT
- #ifdef _I386
- extern char *getcwd();
- buf = cwdbuf;
- return(getcwd(buf,CWDBL));
- #else
- extern char *getwd();
- buf = cwdbuf;
- return(getwd(buf));
- #endif /* _I386 */
- #else
- #ifdef OS2
- #ifndef __IBMC__ /* which has a macro for this */
- extern char *getcwd();
- #endif /* __IBMC__ */
- buf = cwdbuf;
- return(getcwd(buf,CWDBL));
- #else
- #ifdef BSD4
- extern char *getwd();
- buf = cwdbuf;
- return(getwd(buf));
- #else
- return("directory unknown");
- #endif /* BSD4 */
- #endif /* OS2 */
- #endif /* COHERENT */
- #endif /* SYSVORPOSIX */
- #endif /* BSD44 */
- }
-
- /* Z X C M D -- Run a system command so its output can be read like a file */
-
- int
- zxcmd(filnum,comand) int filnum; char *comand; {
- #ifdef OS2
- if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
- if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
- return(0);
- if (filnum == ZIFILE || filnum == ZRFILE) { /* Input from a command */
- if (priv_chk() || ((fp[filnum] = popen(comand,"r")) == NULL))
- return(0);
- } else { /* Output to a command */
- if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
- return(0);
- }
- ispipe[filnum] = 1;
- return(1);
- #else /* Not OS2 */
- int pipes[2];
- int out;
-
- if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
- if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
- return(0);
-
- out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
-
- /* Output to a command */
-
- if (out) { /* Need popen() to do this. */
- #ifdef NOPOPEN
- return(0); /* no popen(), fail. */
- #else
- /* Use popen() to run the command. */
-
- #ifdef _POSIX_SOURCE
- /* Strictly speaking, popen() is not available in POSIX.1 */
- #define DCLPOPEN
- #endif /* _POSIX_SOURCE */
-
- #ifdef COHERENT
- #define DCLPOPEN
- FILE * fdopen();
- #endif /* COHERENT */
-
- #ifdef DCLPOPEN
- /* popen() needs declaring because it's not declared in <stdio.h> */
- FILE *popen();
- #endif /* DCLPOPEN */
-
- if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
- return(0);
- else return(1);
- #endif /* NOPOPEN */
- }
-
- /* Input from a command */
-
- if (pipe(pipes) != 0) {
- debug(F100,"zxcmd pipe failure","",0);
- return(0); /* can't make pipe, fail */
- }
-
- /* Create a fork in which to run the named process */
-
- #ifdef aegis
- if ((pid = vfork()) == 0) { /* child */
- #else
- if ((pid = fork()) == 0) { /* child */
- #endif
-
- /* We're in the fork. */
-
- char *shpath, *shname, *shptr; /* Find user's preferred shell */
- #ifndef aegis
- struct passwd *p;
- char *defshell = "/bin/sh"; /* default shell */
- #endif /* aegis */
- if (priv_can()) exit(1); /* Turn off any privileges! */
- debug(F101,"zxcmd pid","",pid);
- close(pipes[0]); /* close input side of pipe */
- close(0); /* close stdin */
- if (open("/dev/null",0) < 0) return(0); /* replace input by null */
- #ifndef OXOS
- #ifndef SVORPOSIX
- dup2(pipes[1],1); /* BSD: replace stdout & stderr */
- dup2(pipes[1],2); /* by the pipe */
- #else
- close(1); /* AT&T: close stdout */
- if ( dup(pipes[1]) != 1 ) /* Send stdout to the pipe */
- return(0);
- close(2); /* Send stderr to the pipe */
- if ( dup(pipes[1]) != 2 )
- return(0);
- #endif /* SVORPOSIX */
- #else /* OXOS */
- dup2(pipes[1],1);
- dup2(pipes[1],2);
- #endif /* OXOS */
- close(pipes[1]); /* Don't need this any more. */
-
- #ifdef aegis
- if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh";
- #else
- shpath = getenv("SHELL"); /* What shell? */
- if (shpath == NULL) {
- p = getpwuid( real_uid() ); /* Get login data */
- if (p == (struct passwd *)NULL || !*(p->pw_shell))
- shpath = defshell;
- else shpath = p->pw_shell;
- }
- #endif /* aegis */
- shptr = shname = shpath;
- while (*shptr != '\0')
- if (*shptr++ == '/')
- shname = shptr;
- debug(F100,"zxcmd...","",0);
- debug(F110,shpath,shname,0);
-
- execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
- exit(0); /* just punt if it failed. */
- } else if (pid == (PID_T) -1) {
- debug(F100,"zxcmd fork failure","",0);
- return(0);
- }
- debug(F101,"zxcmd pid","",pid);
- if (out) {
- close(pipes[0]); /* Don't need the input side */
- fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
- fp[ZSYSFN] = fp[filnum]; /* Remember. */
- zoutcnt = 0; /* (PWP) reset input buffer */
- zoutptr = zoutbuffer;
- } else {
- close(pipes[1]); /* Don't need the output side */
- fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
- fp[ZSYSFN] = fp[filnum]; /* Remember. */
- zincnt = 0; /* (PWP) reset input buffer */
- zinptr = zinbuffer;
- }
- return(1);
- #endif /* OS2 */
- }
-
- /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
-
- int
- zclosf(filnum) int filnum; {
- int wstat;
- debug(F101,"zclosf filnum","",filnum);
- #ifndef NOPOPEN
- #ifdef OS2
- if (ispipe[filnum]) {
- int x;
- x = pclose(fp[filnum]);
- fp[filnum] = NULL;
- ispipe[filnum] = 0;
- #else
- if (filnum == ZWFILE) {
- int x;
- x = pclose(fp[filnum]);
- fp[filnum] = fp[ZSYSFN] = NULL;
- #endif /* OS2 */
- return((x < 0) ? 0 : 1);
- }
- #endif /* NOPOPEN */
- debug(F101,"zclosf fp[filnum]","", fp[filnum]);
- debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
- #ifdef OS2
- fclose(fp[filnum]);
- fp[filnum] = NULL;
- #else
- if (pid != (PID_T) 0) {
- debug(F101,"zclosf killing pid","",pid);
- kill(pid,9);
- while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
- pid = 0;
- }
- fclose(fp[filnum]);
- fp[filnum] = fp[ZSYSFN] = NULL;
- #endif /* OS2 */
- return(1);
- }
-
- /* Z X P A N D -- Expand a wildcard string into an array of strings */
- /*
- Returns the number of files that match fn1, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- Depends on external variable wildxpand: 0 means we expand wildcards
- internally, nonzero means we call the shell to do it.
- */
-
- int
- zxpand(fn) char *fn; {
- char *p;
-
- #ifdef DTILDE /* Built with tilde-expansion? */
- char *tnam;
- #endif /* DTILDE */
- debug(F111,"zxpand entry",fn,wildxpand);
- #ifdef DTILDE /* Built with tilde-expansion? */
- if (*fn == '~') { /* Starts with tilde? */
- tnam = tilde_expand(fn); /* Try to expand it. */
- if (tnam) fn = tnam;
- }
- debug(F110,"zxpand after tilde_x",fn,0);
- #endif /* DTILDE */
- #ifndef OS2
- if (wildxpand) /* Who is expanding wildcards? */
- fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
- else
- #endif /* OS2 */
- fcount = fgen(fn,mtchs,MAXWLD); /* Kermit */
- if (fcount > 0) {
- mtchptr = mtchs; /* Save pointer for next. */
- }
- if (fcount > 0) {
- debug(F111,"zxpand ok",mtchs[0],fcount);
- return(fcount);
- }
- debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
- p = malloc((int)strlen(fn) + 10); /* Make space */
- if (!p) return(0);
- zrtol(fn,p); /* Try again, maybe lowercase */
- #ifndef OS2
- if (wildxpand)
- fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
- else
- #endif /* OS2 */
- fcount = fgen(p,mtchs,MAXWLD); /* Kermit */
- if (fcount > 0) { /* Got one? */
- mtchptr = mtchs; /* Save pointer for next. */
- debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
- } else debug(F111,"zxpand 2 not ok",p,fcount);
- free(p);
- return(fcount);
- }
-
-
- /* Z N E X T -- Get name of next file from list created by zxpand(). */
- /*
- Returns >0 if there's another file, with its name copied into the arg string,
- or 0 if no more files in list.
- */
- int
- znext(fn) char *fn; {
- if (fcount-- > 0) strcpy(fn,*mtchptr++);
- else *fn = '\0';
- debug(F111,"znext",fn,fcount+1);
- return(fcount+1);
- }
-
-
- /* Z C H K S P A -- Check if there is enough space to store the file */
-
- /*
- Call with file specification f, size n in bytes.
- Returns -1 on error, 0 if not enough space, 1 if enough space.
- */
- int
- #ifdef CK_ANSIC
- zchkspa(char *f, long n)
- #else
- zchkspa(f,n) char *f; long n;
- #endif /* CK_ANSIC */
- /* zchkspa() */ {
- #ifdef OS2
- /* OS/2 gives us an easy way to do this. */
- if (isalpha(f[0]) && f[1] == ':')
- return(zdskspace(toupper(f[0]) - 'A' + 1) >= n);
- else
- return(zdskspace(0) >= n);
- #else
- /* In UNIX there is no good (and portable) way. */
- return(1); /* Always say OK. */
- #endif /* OS2 */
- }
-
-
- /* Z N E W N -- Make a new name for the given file */
-
- /*
- Given the name, fn, of a file that already exists, this function builds a
- new name of the form "<oldname>.~<n>~", where <oldname> is argument name
- (fn), and <n> is a version number, one higher than any existing version
- number for that file, up to 9999. This format is consistent with that used
- by GNU EMACS. If the constructed name is too long for the system's maximum,
- enough characters are truncated from the end of <fn> to allow the version
- number to fit. If no free version numbers exist between 1 and 9999, a
- version number of "xxxx" is used. Returns a pointer to the new name in
- argument s.
- */
-
- VOID
- znewn(fn,s) char *fn, **s; {
- #ifdef pdp11
- #define ZNEWNBL 63 /* Name buffer length */
- #define ZNEWNMD 3 /* Max digits for version number */
- #else
- #define ZNEWNBL 255
- #define ZNEWNMD 4
- #endif /* pdp11 */
-
- static char buf[ZNEWNBL+1];
- char *bp, *xp, *yp;
- #ifdef OS2
- char *zp, ch, temp[14];
- #endif /* OS2 */
- int len = 0, d = 0, n, t, i, j, k, power = 1;
-
- int max = MAXNAMLEN; /* Maximum name length */
-
- if (max < 14) max = 14; /* Make it reasonable */
- if (max > ZNEWNBL) max = ZNEWNBL;
- bp = buf; /* Buffer for building new name */
- yp = fn;
- while (*yp) { /* Copy old name into buffer */
- *bp++ = *yp++;
- if (len++ > ZNEWNBL) break; /* ...up to buffer length */
- }
- *s = NULL;
- for (i = 1; i < ZNEWNMD + 1; i++) { /* Version numbers up to 10**i - 1 */
- power *= 10; /* Next power of 10 */
- j = max - len; /* Space left for version number */
- k = 3 + i; /* Space needed for it */
- if (j < k) { /* Make room if necessary */
- len -= (k - j); /* Adjust length of filename */
- bp = buf + len; /* Point to new end */
- }
- *bp++ = '*'; /* Put a star on the end (UNIX) */
- *bp-- = '\0'; /* Terminate with null */
-
- n = zxpand(buf); /* Expand the resulting wild name */
- /* n is the number of matches */
- while (n-- > 0) { /* Find any existing name.~n~ files */
- xp = *mtchptr++; /* Point at matching name */
- xp += len; /* Look for .~<n>~ at the end of it */
- if (*xp == '.' && *(xp+1) == '~') { /* Has a version number */
- t = atoi(xp+2); /* Get it */
- if (t > d) d = t; /* Save d = highest version number */
- }
- }
- if (d < power-1) { /* Less than maximum possible? */
- sprintf(bp,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
- *s = buf; /* Point to new name */
- break; /* Done, return it */
- }
- }
- if (*s == NULL) {
- sprintf(bp,".~xxxx~"); /* Too many, use xxxx. */
- *s = buf;
- }
- #ifdef OS2
- if (IsFileNameValid(buf))
- return; /* HPFS */
- /* otherwise make FAT 8.3 name */
- xp = bp = buf;
- yp = fn;
- while (*yp) { /* Copy name into buf */
- ch = *bp++ = *yp++;
- if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
- }
- *bp = '\0';
- yp = xp;
- i = 1;
- while (*yp && (*yp != '.')) {
- yp++;
- if (++i<=6) zp=yp;
- }
- /* zp points to 6th character in name, or yp, whichever occurs first. */
- strcpy(temp,yp); /* Copy extension, if any */
- while (zp != xp+8) {
- if ( zp < xp+5 ) *zp++='0';
- else *zp++='?'; /* Pad out with wild cards */
- }
- strcpy(zp,temp); /* Get the extension back */
- n = zxpand(buf); /* Expand the resulting wild name */
- d = 0; /* Index number */
- while (znext(temp)) {
- i = atoi(temp+5);
- if (i > d) d = i;
- }
- sprintf(temp,"%03d",d+1); /* get the number into a string */
- memcpy(xp+5, temp, 3);
- #endif /* OS2 */
- return;
- }
-
-
- /* Z R E N A M E -- Rename a file */
-
- /* Note, link() and unlink() are used because rename() is not available */
- /* in some versions of UNIX. */
- /* Call with old and new names */
- /* Returns 0 on success, -1 on failure. */
-
- int
- zrename(old,new) char *old, *new; {
- #ifdef RENAME
- /*
- Atomic, preferred.
- */
- return(rename(old, new));
- #else /* !RENAME */
- /*
- This way has a window of vulnerability.
- */
- if (link(old,new) < 0) { /* Make a link with the new name. */
- debug(F111,"zrename link fails, errno",old,errno);
- return(-1);
- }
- if (unlink(old) < 0) { /* Unlink the old name. */
- debug(F111,"zrename unlink fails, errno",old,errno);
- return(-1);
- }
- return(0);
- #endif /* RENAME */
- }
-
- /* Z S A T T R */
- /*
- Fills in a Kermit file attribute structure for the file which is to be sent.
- Returns 0 on success with the structure filled in, or -1 on failure.
- If any string member is null, then it should be ignored.
- If any numeric member is -1, then it should be ignored.
- */
- int
- zsattr(xx) struct zattr *xx; {
- long k;
-
- k = iflen % 1024L; /* File length in K */
- if (k != 0L) k = 1L;
- xx->lengthk = (iflen / 1024L) + k;
- xx->type.len = 0; /* File type can't be filled in here */
- xx->type.val = "";
- if (*nambuf) {
- xx->date.val = zfcdat(nambuf); /* File creation date */
- xx->date.len = (int)strlen(xx->date.val);
- } else {
- xx->date.len = 0;
- xx->date.val = "";
- }
- xx->creator.len = 0; /* File creator */
- xx->creator.val = "";
- xx->account.len = 0; /* File account */
- xx->account.val = "";
- xx->area.len = 0; /* File area */
- xx->area.val = "";
- xx->passwd.len = 0; /* Area password */
- xx->passwd.val = "";
- xx->blksize = -1L; /* File blocksize */
- xx->access.len = 0; /* File access */
- xx->access.val = "";
- xx->encoding.len = 0; /* Transfer syntax */
- xx->encoding.val = 0;
- xx->disp.len = 0; /* Disposition upon arrival */
- xx->disp.val = "";
- xx->lprotect.len = 0; /* Local protection */
- xx->lprotect.val = "";
- xx->gprotect.len = 0; /* Generic protection */
- xx->gprotect.val = "";
- xx->systemid.len = 2; /* System ID */
- xx->systemid.val = "U1";
- xx->recfm.len = 0; /* Record format */
- xx->recfm.val = "";
- xx->sysparam.len = 0; /* System-dependent parameters */
- xx->sysparam.val = "";
- xx->length = iflen; /* Length */
- return(0);
- }
-
- /* Z F C D A T -- Get file creation date */
- /*
- Call with pointer to filename.
- On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
- On failure, returns pointer to null string.
- */
- static char datbuf[40];
-
- /* static */ /* (===OS2 change===) */
- char *
- zfcdat(name) char *name; {
-
- #ifdef TIMESTAMP
- struct stat buffer;
- struct tm *time_stamp, *localtime();
- int yy, ss;
-
- datbuf[0] = '\0';
- if(stat(name,&buffer) != 0) {
- debug(F110,"zfcdat stat failed",name,0);
- return("");
- }
- time_stamp = localtime(&(buffer.st_mtime));
- yy = time_stamp->tm_year;
- if (yy < 100) /* In case it returns 2-digit year? */
- yy += 1900;
- if (yy < 0 || yy > 9999) { /* Make sure year is ok */
- debug(F110,"zfcdat date failed",name,0);
- return("");
- }
- if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
- return("");
- if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
- return("");
- if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
- return("");
- if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
- return("");
- ss = time_stamp->tm_sec; /* Seconds */
- if (ss < 0 || ss > 59) /* Some systems give a BIG number */
- ss = 0;
- sprintf(datbuf,
- #ifdef pdp11
- /* For some reason, 2.1x BSD sprintf gets the last field wrong. */
- "%04d%02d%02d %02d:%02d:00",
- #else
- "%04d%02d%02d %02d:%02d:%02d",
- #endif /* pdp11 */
- yy,
- time_stamp->tm_mon + 1,
- time_stamp->tm_mday,
- time_stamp->tm_hour,
- time_stamp->tm_min
- #ifndef pdp11
- , ss
- #endif /* pdp11 */
- );
- yy = (int)strlen(datbuf);
- debug(F111,"zfcdat",datbuf,yy);
- if (yy > 17) datbuf[17] = '\0';
- return(datbuf);
- #else
- return("");
- #endif /* TIMESTAMP */
- }
-
- /* Z S T I M E -- Set creation date for incoming file */
- /*
- Call with:
- f = pointer to name of existing file.
- yy = pointer to a Kermit file attribute structure in which yy->date.val
- is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
- x = is a function code: 0 means to set the file's creation date as given.
- 1 means compare the given date with the file creation date.
- Returns:
- -1 on any kind of error.
- 0 if x is 0 and the file date was set successfully.
- 0 if x is 1 and date from attribute structure <= file creation date.
- 1 if x is 1 and date from attribute structure > file creation date.
- */
- int
- zstime(f,yy,x) char *f; struct zattr *yy; int x; {
- int r = -1; /* return code */
- /*
- It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se.
- */
- #ifdef TIMESTAMP
- /*
- To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
- is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
- */
- #ifndef OS2
- #ifndef ODT30
- extern int ftime();
- extern int stat();
- #endif /* ODT30 */
- #ifdef BSD44
- extern int utimes();
- #else
- extern int utime();
- #endif /* BSD44 */
- /* at least, the declarations for int functions are not needed anyway */
- extern struct tm *localtime();
- /* and this should have been declared always through a header file */
- #endif /* OS2 */
- long tm, days;
- int i, n, isleapyear;
- /* J F M A M J J A S O N D */
- /* 31 28 31 30 31 30 31 31 30 31 30 31 */
- static
- int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
- char s[5];
- struct stat sb;
- #ifdef BSD44
- struct timeval tp[2];
- #else
- #ifdef OS2
- struct utimbuf tp;
- #ifdef __EMX__
- long timezone;
- struct timeb tbp;
- #endif /* __EMX__ */
- #else
- #ifdef V7
- struct utimbuf {
- time_t timep[2]; /* New access and modificaton time */
- } tp;
- char *tz;
- long timezone; /* In case timezone not defined in .h file */
- #else
- #ifdef SYSUTIMEH
- struct utimbuf tp;
- #else
- struct utimbuf {
- time_t atime; /* New access time */
- time_t mtime; /* New modification time */
- } tp;
- #endif /* SYSUTIMEH */
- #endif /* V7 */
- #endif /* OS2 */
- #endif /* BSD44 */
-
- #ifdef ANYBSD
- long timezone;
- static struct timeb tbp;
- #endif /* ANYBSD */
-
- debug(F110,"zstime",f,0);
-
- if ((yy->date.len == 0)
- || (yy->date.len != 17)
- || (yy->date.val[8] != ' ')
- || (yy->date.val[11] != ':')
- || (yy->date.val[14] != ':') ) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
- for(i = 0; i < 8; i++) {
- if (!isdigit(yy->date.val[i])) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
- i++;
-
- for (; i < 16; i += 3) {
- if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"zstime date check 3",yy->date.val,yy->date.len);
-
- #ifdef ANYBSD
- debug(F100,"ztime BSD calling ftime","",0);
- ftime(&tbp);
- debug(F100,"ztime BSD back from ftime","",0);
- timezone = tbp.timezone * 60L;
- debug(F101,"ztime BSD timezone","",timezone);
- #endif /* ANYBSD */
-
- #ifdef OS2
- #ifdef __EMX__
- ftime(&tbp);
- timezone = tbp.timezone * 60L;
- #endif /* __EMX__ */
- #endif /* OS2 */
-
- #ifdef SVORPOSIX
- tzset(); /* Set timezone */
- #endif /* SVORPOSIX */
-
- #ifdef V7
- if ((tz = getenv("TZ")) == NULL)
- timezone = 0; /* UTC/GMT */
- else
- timezone = atoi(&tz[3]); /* Set 'timezone'. */
- timezone *= 60L;
- #endif /* V7 */
-
- debug(F100,"zstime so far so good","",0);
-
- s[4] = '\0';
- for (i = 0; i < 4; i++) /* Fix the year */
- s[i] = yy->date.val[i];
-
- n = atoi(s);
-
- debug(F111,"zstime year",s,n);
-
- /* Previous year's leap days. This won't work after year 2100. */
-
- isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
- days = (long) (n - 1970) * 365;
- days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
-
- s[2] = '\0';
-
- for (i = 4 ; i < 16; i += 2) {
- s[0] = yy->date.val[i];
- s[1] = yy->date.val[i + 1];
- n = atoi(s);
- switch (i) {
- case 4: /* MM: month */
- if ((n < 1 ) || ( n > 12)) {
- debug(F111,"zstime 4 bad date ",yy->date.val,yy->date.len);
- return(-1);
- }
- days += monthdays [n];
- if (isleapyear && n > 2)
- ++days;
- continue;
-
- case 6: /* DD: day */
- if ((n < 1 ) || ( n > 31)) {
- debug(F111,"zstime 6 bad date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm = (days + n - 1) * 24L * 60L * 60L;
- i++; /* Skip the space */
- continue;
-
- case 9: /* hh: hour */
- if ((n < 0 ) || ( n > 23)) {
- debug(F111,"zstime 9 bad date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n * 60L * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 12: /* mm: minute */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zstime 12 bad date ",yy->date.val,yy->date.len);
- return(-1);
- }
- #ifdef ANYBSD /* Correct for time zone */
- tm += timezone;
- #else
- #ifndef BSD44 /* For now... */
- #ifndef CONVEX9
- /*
- How to accomplish this for these systems is still a mystery.
- */
- #ifdef ultrix
- tm += (long) timezone;
- #else
- tm += timezone;
- #endif /* ultrix */
- #endif /* CONVEX9 */
- #endif /* BSD44 */
- #endif /* ANYBSD */
- tm += n * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 15: /* ss: second */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zstime 15 bad date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n;
- }
- if (localtime(&tm)->tm_isdst)
- tm -= 60L * 60L; /* Adjust for daylight savings time */
- }
- debug(F101,"tm","",tm);
- debug(F111,"A-pkt date ok ",yy->date.val,yy->date.len);
-
- if (stat(f,&sb)) { /* Get the time for the file */
- debug(F110,"Can't stat file:",f,0);
- return(-1);
- }
- debug(F101,"sb.st_atime","",sb.st_atime);
-
- #ifdef OS2
- tp.modtime = tm; /* Set modif. time to creation date */
- tp.actime = sb.st_atime; /* Don't change the access time */
- #else
- #ifdef SYSUTIMEH
- tp.modtime = tm; /* Set modif. time to creation date */
- tp.actime = sb.st_atime; /* Don't change the access time */
- #else
- #ifdef V7
- tp.timep[0] = tm; /* Set modif. time to creation date */
- tp.timep[1] = sb.st_atime; /* Don't change the access time */
- #else
- #ifdef BSD44
- tp[0].tv_sec = sb.st_atime; /* Access time first */
- tp[1].tv_sec = tm; /* Update time second */
- #else
- tp.mtime = tm; /* Set modif. time to creation date */
- tp.atime = sb.st_atime; /* Don't change the access time */
- #endif /* BSD44 */
- #endif /* V7 */
- #endif /* SYSUTIMEH */
- #endif /* OS2 */
-
- switch (x) { /* Execute desired function */
- case 0: /* Set the creation date of the file */
- if (
- #ifdef BSD44
- utimes(f,tp)
- #else
- utime(f,&tp)
- #endif /* BSD44 */
- ) { /* Fix modification time */
- debug(F110,"Can't set modification time for file: ",f,0);
- r = -1;
- } else {
- debug(F110,"Modification time is set for file: ",f,0);
- r = 0;
- }
- break;
- case 1: /* Compare the dates */
- /*
- This was st_atime, which was wrong. We want the file-data modification
- time, st_mtime.
- */
- debug(F111,"zstime compare",f,sb.st_mtime);
- debug(F111,"zstime compare","packet",tm);
- r = (sb.st_mtime < tm) ? 0 : 1;
- break;
- default: /* Error */
- r = -1;
- }
- #endif /* TIMESTAMP */
- return(r);
- }
-
- /* Find initialization file. */
-
- #ifdef NOTUSED
- int
- zkermini() {
- /* nothing here for Unix. This function added for benefit of VMS Kermit. */
- return(0);
- }
- #endif /* NOTUSED */
-
- #ifndef NOFRILLS
- int
- zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
- /*
- Returns 0 on success
- 2 if mail delivered but temp file can't be deleted
- -2 if mail can't be delivered
- The UNIX version always returns 0 because it can't get a good return
- code from zsyscmd.
- */
- #ifdef BSD4
- /* The idea is to use /usr/ucb/mail, rather than regular mail, so that */
- /* a subject line can be included with -s. Since we can't depend on the */
- /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
- /* and even if Mail has been moved to somewhere else, this should still */
- /* find it... The search could be made more reliable by actually using */
- /* access() to see if /usr/ucb/Mail exists. */
-
- /* Should also make some check on zmbuf overflow... */
-
- #ifdef DGUX540
- sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
- #else
- sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
- #endif /* DGUX540 */
- zsyscmd(zmbuf);
- #else
- #ifdef SVORPOSIX
- #ifndef OXOS
- sprintf(zmbuf,"mail %s < %s", p, f);
- #else /* OXOS */
- sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
- #endif /* OXOS */
- zsyscmd(zmbuf);
- #else
- *zmbuf = '\0';
- #endif
- #endif
- return(0);
- }
- #endif /* NOFRILLS */
-
- #ifndef NOFRILLS
- int
- zprint(p,f) char *p; char *f; { /* Print file f with options p */
-
- #ifdef OS2
- sprintf(zmbuf,"print %s %s", p, f); /* Construct print command */
- zsyscmd(zmbuf);
- #else
- #ifdef UNIX
- #ifdef ANYBSD /* BSD uses lpr to spool */
- #ifdef DGUX540 /* And DG/UX */
- #define SPOOLER "lp"
- #else
- #define SPOOLER "lpr"
- #endif /* DGUX540 */
- #else /* Sys V uses lp */
- #ifdef TRS16 /* except for Tandy-16/6000... */
- #define SPOOLER "lpr"
- #else
- #define SPOOLER "lp"
- #endif
- #endif
- /*
- Note use of standard input redirection. In some systems, lp[r] runs
- setuid to lp (or ...?), so if user has sent a file into a directory
- that lp does not have read access to, it can't be printed unless it is
- feed to lp[r] as standard input.
- */
- sprintf(zmbuf,"%s %s < %s", SPOOLER, p, f); /* Construct print command */
- zsyscmd(zmbuf);
- #else /* Not UNIX */
- *zmbuf = '\0';
- #endif /* UNIX */
- #endif /* OS2 */
- return(0);
- }
- #endif /* NOFRILLS */
-
- /*
- Wildcard expansion functions. C-Kermit used to insist on doing this itself
- New code (version 5A, 1990-91) gives user option to ask UNIX to do it.
- This lets users use the wildcard expansion features of their favorite shell.
- Operation is slower because of the forking & piping, but flexibility is
- greater and program is smaller. For OS/2, C-Kermit still does this itself.
- */
- static char scratch[MAXPATH+4]; /* Used by both methods */
-
- #ifndef OS2
- static int oldmtchs = 0; /* Let shell (ls) expand them. */
- #ifdef COMMENT
- static char *lscmd = "/bin/ls -d"; /* Command to use. */
- #else
- static char *lscmd = "echo"; /* Command to use. */
- #endif /* COMMENT */
-
- int
- shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
- char *fgbuf = NULL; /* Buffer for forming ls command */
- char *p, *q; /* Workers */
- int i, x, retcode; char c; /* ... */
-
- x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
- for (i = 0; i < oldmtchs; i++) /* Free previous file list */
- free(namlst[i]);
- fgbuf = malloc(x); /* Get buffer for command */
- if (!fgbuf) return(-1); /* Fail if cannot */
- sprintf(fgbuf,"%s %s",lscmd,pat); /* Form the command */
- zxcmd(ZIFILE,fgbuf); /* Start the command */
- i = 0; /* File counter */
- p = scratch; /* Point to scratch area */
- retcode = -1; /* Assume failure */
- while ((x = zminchar()) != -1) { /* Read characters from command */
- c = (char) x;
- if (c == ' ' || c == '\n') { /* Got newline or space? */
- *p = '\0'; /* Yes, terminate string */
- p = scratch; /* Point back to beginning */
- if (zchki(p) == -1) /* Does file exist? */
- continue; /* No, continue */
- x = (int)strlen(p); /* Yes, get length of name */
- q = malloc(x+1); /* Allocate space for it */
- if (!q) goto shxfin; /* Fail if space can't be obtained */
- strcpy(q,scratch); /* Copy name to space */
- namlst[i++] = q; /* Copy pointer to name into array */
- if (i > len) goto shxfin; /* Fail if too many */
- } else { /* Regular character */
- *p++ = c; /* Copy it into scratch area */
- }
- }
- retcode = i; /* Return number of matching files */
- shxfin: /* Common exit point */
- free(fgbuf); /* Free command buffer */
- zclosf(ZIFILE); /* Delete the command fork. */
- oldmtchs = i; /* Remember how many files */
- return(retcode);
- }
- #endif /* OS2 */
-
- /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
-
- /* Define the size of the string space for filename expansion. */
-
- #ifndef DYNAMIC
- #ifdef PROVX1
- #define SSPACE 500
- #else
- #ifdef BSD29
- #define SSPACE 500
- #else
- #ifdef pdp11
- #define SSPACE 500
- #else
- #ifdef aegis
- #define SSPACE 10000 /* size of string-generating buffer */
- #else /* Default static buffer size */
- #define SSPACE 2000 /* size of string-generating buffer */
- #endif /* aegis */
- #endif /* pdp11 */
- #endif /* BSD29 */
- #endif /* PROVX1 */
- static char sspace[SSPACE]; /* buffer for generating filenames */
- #else /* DYNAMIC */
- #define SSPACE 10000
- static char *sspace = (char *)0;
- #endif /* DYNAMIC */
- #ifdef aegis
- static char bslash;
- #endif /* aegis */
- static int ssplen = SSPACE; /* length of string space buffer */
-
- static char *freeptr,**resptr; /* copies of caller's arguments */
- static int remlen; /* remaining length in caller's array*/
- static int numfnd; /* number of matches found */
-
- /*
- * splitpath:
- * takes a string and splits the slash-separated portions into
- * a list of path structures. Returns the head of the list. The
- * structures are allocated by malloc, so they must be freed.
- * Splitpath is used internally by the filename generator.
- *
- * Input: A string.
- * Returns: A linked list of the slash-separated segments of the input.
- */
-
- struct path *
- splitpath(p) char *p; {
- struct path *head,*cur,*prv;
- int i;
-
- debug(F110,"splitpath",p,0);
-
- head = prv = NULL;
- if (ISDIRSEP(*p)) p++; /* skip leading slash */
- while (*p != '\0') {
- cur = (struct path *) malloc(sizeof (struct path));
- debug(F101,"splitpath malloc","",cur);
- if (cur == NULL) {
- debug(F100,"splitpath malloc failure","",0);
- return((struct path *)NULL);
- }
- cur -> fwd = NULL;
- if (head == NULL)
- head = cur;
- else
- prv -> fwd = cur; /* link into chain */
- prv = cur;
- #ifdef aegis
- /* treat backslash as "../" */
- if (bslash && *p == bslash) {
- strcpy(cur->npart, "..");
- ++p;
- } else {
- for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
- cur -> npart[i] = *p++;
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN)
- while (*p && *p != '/' && *p != bslash)
- p++;
- }
- if (*p == '/') p++;
- #else
- #ifdef OS2
- for (i = 0;
- i < MAXNAMLEN && !ISDIRSEP(*p) && *p != ':' && *p != '\0';
- i++ )
- cur -> npart[i] = *p++;
- if ( *p == ':' ) {
- cur -> npart[i++] = *p++;
- if ( !ISDIRSEP(*p) )
- cur -> npart[i++] = '.';
- }
- #else
- for (i=0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
- cur -> npart[i] = *p++;
- }
- #endif /* OS2 */
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN)
- while (!ISDIRSEP(*p) && *p != '\0') p++;
- if (ISDIRSEP(*p))
- p++;
-
- #endif /* aegis */
- }
- return(head);
- }
-
- /*
- * fgen:
- * This is the actual name generator. It is passed a string,
- * possibly containing wildcards, and an array of character pointers.
- * It finds all the matching filenames and stores them into the array.
- * The returned strings are allocated from a static buffer local to
- * this module (so the caller doesn't have to worry about deallocating
- * them); this means that successive calls to fgen will wipe out
- * the results of previous calls. This isn't a problem here
- * because we process one wildcard string at a time.
- *
- * Input: a wildcard string, an array to write names to, the
- * length of the array.
- * Returns: the number of matches. The array is filled with filenames
- * that matched the pattern. If there wasn't enough room in the
- * array, -1 is returned.
- * Originally by: Jeff Damens, CUCCA, 1984. Many changes since then.
- */
- static int
- fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
- struct path *head;
- char *sptr;
- #ifdef aegis
- char *namechars;
- int tilde = 0, bquote = 0;
-
- if ((namechars = getenv("NAMECHARS")) != NULL) {
- if (xindex(namechars, '~' ) != NULL) tilde = '~';
- if (xindex(namechars, '\\') != NULL) bslash = '\\';
- if (xindex(namechars, '`' ) != NULL) bquote = '`';
- } else {
- tilde = '~'; bslash = '\\'; bquote = '`';
- }
-
- sptr = scratch;
-
- /* copy "`node_data", etc. anchors */
- if (bquote && *pat == bquote)
- while (*pat && *pat != '/' && *pat != bslash)
- *sptr++ = *pat++;
- else if (tilde && *pat == tilde)
- *sptr++ = *pat++;
- while (*pat == '/')
- *sptr++ = *pat++;
- if (sptr == scratch) {
- strcpy(scratch,"./");
- sptr = scratch+2;
- } /* init buffer correctly */
- if (!(head = splitpath(pat))) return(-1);
- #else /* not aegis */
- debug(F110,"fgen pat",pat,0);
- if (!(head = splitpath(pat))) return(-1);
- sptr = scratch;
- if (!ISDIRSEP(*pat))
- *sptr++ = '.'; /* init buffer correctly */
- *sptr++ = DIRSEP;
- #ifdef OS2
- if (isalpha(pat[0]) && pat[1] == ':')
- sptr = scratch; /* reset in case of leading drive: */
- #endif /* OS2 */
- #endif /* aegis */
- numfnd = 0; /* none found yet */
- #ifdef DYNAMIC
- if (!sspace) { /* Need to allocate string space? */
- while (ssplen > 50) {
- if ((sspace = malloc(ssplen+2))) { /* Got it. */
- debug(F101,"fgen string space","",ssplen);
- break;
- }
- ssplen = (ssplen / 2) + (ssplen / 4); /* Didn't, reduce by 3/4 */
- }
- if (ssplen <= 50) { /* Did we get it? */
- fprintf(stderr,"fgen can't malloc string space\n");
- return(-1);
- }
- }
- #endif /* DYNAMIC */
- freeptr = sspace; /* this is where matches are copied */
- resptr = resarry; /* static copies of these so */
- remlen = len; /* recursive calls can alter them */
- traverse(head,scratch,sptr); /* go walk the directory tree */
- #ifdef COMMENT
- /*
- This code, circa 1984, has never worked right - it references the head
- pointer after it has already been freed. Lord knows what might have been
- happening because of this. Thanks to Steve Walton for finding & fixing
- this bug.
- */
- for (; head != NULL; head = head -> fwd)
- free(head); /* return the path segments */
- #else
- while (head != NULL) {
- struct path *next = head -> fwd;
- free(head);
- head = next;
- }
- #endif /* COMMENT */
- return(numfnd); /* and return the number of matches */
- }
-
- /* traverse:
- * Walks the directory tree looking for matches to its arguments.
- * The algorithm is, briefly:
- * If the current pattern segment contains no wildcards, that
- * segment is added to what we already have. If the name so far
- * exists, we call ourselves recursively with the next segment
- * in the pattern string; otherwise, we just return.
- *
- * If the current pattern segment contains wildcards, we open the name
- * we've accumulated so far (assuming it is really a directory), then read
- * each filename in it, and, if it matches the wildcard pattern segment, add
- * that filename to what we have so far and call ourselves recursively on the
- * next segment.
- *
- * Finally, when no more pattern segments remain, we add what's accumulated
- * so far to the result array and increment the number of matches.
- *
- * Input: a pattern path list (as generated by splitpath), a string
- * pointer that points to what we've traversed so far (this
- * can be initialized to "/" to start the search at the root
- * directory, or to "./" to start the search at the current
- * directory), and a string pointer to the end of the string
- * in the previous argument.
- * Returns: nothing.
- */
- static VOID
- traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
-
- /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
- /* LONGFN can also be defined on the cc command line. */
-
- #ifdef BSD29
- #ifndef LONGFN
- #define LONGFN
- #endif
- #endif
-
- #ifdef BSD42
- #ifndef LONGFN
- #define LONGFN
- #endif
- #endif
-
- /* Appropriate declarations for directory routines and structures */
- /* #define OPENDIR means to use opendir(), readdir(), closedir() */
- /* If OPENDIR not defined, we use open(), read(), close() */
-
- #ifdef DIRENT /* New way, <dirent.h> */
- #define OPENDIR
- DIR *fd, *opendir();
- struct dirent *dirbuf;
- struct dirent *readdir();
- #else /* !DIRENT */
- #ifdef LONGFN /* Old way, <dir.h> with opendir() */
- #define OPENDIR
- DIR *fd, *opendir();
- struct direct *dirbuf;
- #else /* !LONGFN */
- int fd; /* Old way, <dir.h> with open() */
- struct direct dir_entry;
- struct direct *dirbuf = &dir_entry;
- #endif /* LONGFN */
- #endif /* DIRENT */
-
- struct stat statbuf; /* for file info */
-
- if (pl == NULL) {
- *--endcur = '\0'; /* end string, overwrite trailing / */
- addresult(sofar);
- return;
- }
- if (!iswild(pl -> npart)) {
- strcpy(endcur,pl -> npart);
- endcur += (int)strlen(pl -> npart);
- *endcur = '\0'; /* end current string */
- if (stat(sofar,&statbuf) == 0) { /* if current piece exists */
- #ifdef OS2
- if (endcur - sofar == 3 && endcur[-1] == '.' && endcur[-2] == ':')
- endcur--;
- else
- #endif /* OS2 */
- *endcur++ = DIRSEP; /* add slash to end */
- *endcur = '\0'; /* and end the string */
- traverse(pl -> fwd,sofar,endcur);
- }
- return;
- }
-
- /* Segment contains wildcards, have to search directory */
-
- *endcur = '\0'; /* end current string */
- if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */
- if (!S_ISDIR (statbuf.st_mode)) return; /* not a directory, skip */
-
- #ifdef OPENDIR
- if ((fd = opendir(sofar)) == NULL) return; /* Can't open, fail. */
- while (dirbuf = readdir(fd))
- #else /* !OPENDIR */
- if ((fd = open(sofar,O_RDONLY)) < 0) return; /* Can't open, fail. */
- while (read(fd, (char *)dirbuf, sizeof dir_entry))
- #endif /* OPENDIR */
- {
- /* Get null-terminated copy!!! */
- strncpy(nambuf,dirbuf->d_name,MAXNAMLEN);
- nambuf[MAXNAMLEN] = '\0';
- #ifdef unos
- if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf))
- #else
- /* #ifdef _POSIX_SOURCE */
- /*
- Directory reading is not specified in POSIX.1. POSIX.2 gives us glob() and
- fnmatch(), which are not yet supported by C-Kermit. Meanwhile, maybe POSIX
- implementations should force "set wildcard shell" and remove all of this
- code.
- */
- #ifdef QNX
- if (dirbuf->d_stat.st_ino != 0 && match(pl -> npart,nambuf))
- #else
- #ifdef SOLARIS
- if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
- #else
- #ifdef sun
- if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
- #else
- #ifdef bsdi
- if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
- #else
- #ifdef __386BSD__
- if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
- #else
- #ifdef ultrix
- if (dirbuf->gd_ino != 0 && match(pl -> npart,nambuf))
- #else
- if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
- #endif /* ultrix */
- #endif /* __386BSD__ */
- #endif /* bsdi */
- #endif /* sun */
- #endif /* SOLARIS */
- #endif /* QNX */
-
- /* #else */ /* not _POSIX_SOURCE */
- /* if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) */
- /* #endif */ /* _POSIX_SOURCE */
-
- #endif /* unos */
- {
- char *eos;
- strcpy(endcur,nambuf);
- eos = endcur + (int)strlen(nambuf);
- *eos++ = DIRSEP; /* end this segment */
- traverse(pl -> fwd,sofar,eos);
- }
- }
- #ifdef OPENDIR
- closedir(fd);
- #else /* !OPENDIR */
- close(fd);
- #endif /* OPENDIR */
- }
-
- /*
- * addresult:
- * Adds a result string to the result array. Increments the number
- * of matches found, copies the found string into our string
- * buffer, and puts a pointer to the buffer into the caller's result
- * array. Our free buffer pointer is updated. If there is no
- * more room in the caller's array, the number of matches is set to -1.
- * Input: a result string.
- * Returns: nothing.
- */
- static VOID
- addresult(str) char *str; {
- int l;
- debug(F111,"addresult",str,remlen);
- if (str[0] == '.' && ISDIRSEP(str[1])) str += 2; /* (===OS2 change===) */
- if (--remlen < 0) {
- numfnd = -1;
- return;
- }
- l = (int)strlen(str) + 1; /* size this will take up */
- if ((freeptr + l) > (sspace + ssplen)) {
- numfnd = -1; /* do not record if not enough space */
- return;
- }
- strcpy(freeptr,str);
- *resptr++ = freeptr;
- freeptr += l;
- numfnd++;
- }
-
- /*
- * match:
- * pattern matcher. Takes a string and a pattern possibly containing
- * the wildcard characters '*' and '?'. Returns true if the pattern
- * matches the string, false otherwise.
- * by: Jeff Damens, CUCCA, 1984
- * skipping over dot files and backslash quoting added by fdc, 1990.
- *
- * Input: a string and a wildcard pattern.
- * Returns: 1 if match, 0 if no match.
- */
- static int
- match(pattern,string) char *pattern,*string; {
- char *psave,*ssave; /* back up pointers for failure */
- int q = 0; /* quote flag */
-
- debug(F110,"match str",string,0);
- psave = ssave = NULL;
- #ifndef MATCHDOT
- if (*string == '.' && *pattern != '.') {
- debug(F110,"match skip",string,0);
- return(0);
- }
- #endif
- while (1) {
- #ifdef OS2
- for (; tolower(*pattern) == tolower(*string); pattern++,string++)
- #else
- for (; *pattern == *string; pattern++,string++) /* skip first */
- #endif /* OS2 */
- if (*string == '\0') return(1); /* end of strings, succeed */
-
- if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
- q = 1; /* metacharacters */
- pattern++; /* advance past quote */
- if (*pattern != *string) return(0);
- continue;
- } else q = 0;
-
- if (q) {
- return(0);
- } else {
- if (*string != '\0' && *pattern == '?') {
- pattern++; /* '?', let it match */
- string++;
- } else if (*pattern == '*') { /* '*' ... */
- psave = ++pattern; /* remember where we saw it */
- ssave = string; /* let it match 0 chars */
- } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
- /* ...have seen a star */
- string = ++ssave; /* skip 1 char from string */
- pattern = psave; /* and back up pattern */
- } else return(0); /* otherwise just fail */
- }
- }
- }
-
- /*
- The following two functions are for expanding tilde in filenames
- Contributed by Howie Kaye, CUCCA, developed for CCMD package.
- */
-
- /* W H O A M I -- Get user's username. */
-
- /*
- 1) Get real uid
- 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
- 3) If $USER's uid is the same as ruid, realname is $USER
- 4) Otherwise get logged in user's name
- 5) If that name has the same uid as the real uid realname is loginname
- 6) Otherwise, get a name for ruid from /etc/passwd
- */
- static char *
- whoami () {
- #ifdef DTILDE
- #ifdef pdp11
- #define WHOLEN 100
- #else
- #define WHOLEN 257
- #endif /* pdp11 */
- static char realname[256]; /* user's name */
- static int ruid = -1; /* user's real uid */
- char loginname[256], envname[256]; /* temp storage */
- char *c;
- struct passwd *p;
- _PROTOTYP(extern char * getlogin, (void) );
-
- if (ruid != -1)
- return(realname);
-
- ruid = real_uid(); /* get our uid */
-
- /* how about $USER or $LOGNAME? */
- if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
- strcpy (envname, c);
- if ((p = getpwnam(envname)) != NULL) {
- if (p->pw_uid == ruid) { /* get passwd entry for envname */
- strcpy (realname, envname); /* if the uid's are the same */
- return(realname);
- }
- }
- }
-
- /* can we use loginname() ? */
-
- if ((c = getlogin()) != NULL) { /* name from utmp file */
- strcpy (loginname, c);
- if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
- if (p->pw_uid == ruid) { /* for loginname */
- strcpy (realname, loginname); /* if the uid's are the same */
- return(realname);
- }
- }
-
- /* Use first name we get for ruid */
-
- if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
- realname[0] = '\0'; /* no user name */
- ruid = -1;
- return(NULL);
- }
- strcpy (realname, p->pw_name);
- return(realname);
- #else
- return(NULL);
- #endif /* DTILDE */
- }
-
- /* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
-
- char *
- tilde_expand(dirname) char *dirname; {
- #ifdef DTILDE
- #ifdef pdp11
- #define BUFLEN 100
- #else
- #define BUFLEN 257
- #endif /* pdp11 */
- struct passwd *user;
- static char olddir[BUFLEN];
- static char oldrealdir[BUFLEN];
- static char temp[BUFLEN];
- int i, j;
-
- debug(F111,"tilde_expand",dirname,dirname[0]);
-
- if (dirname[0] != '~') /* Not a tilde...return param */
- return(dirname);
- if (!strcmp(olddir,dirname)) { /* Same as last time */
- return(oldrealdir); /* so return old answer. */
- } else {
- j = (int)strlen(dirname);
- for (i = 0; i < j; i++) /* find username part of string */
- if (!ISDIRSEP(dirname[i]))
- temp[i] = dirname[i];
- else break;
- temp[i] = '\0'; /* tie off with a NULL */
- if (i == 1) { /* if just a "~" */
- user = getpwnam(whoami()); /* get info on current user */
- } else {
- user = getpwnam(&temp[1]); /* otherwise on the specified user */
- }
- }
- if (user != NULL) { /* valid user? */
- strcpy(olddir, dirname); /* remember the directory */
- strcpy(oldrealdir,user->pw_dir); /* and their home directory */
- strcat(oldrealdir,&dirname[i]);
- return(oldrealdir);
- } else { /* invalid? */
- strcpy(olddir, dirname); /* remember for next time */
- strcpy(oldrealdir, dirname);
- return(oldrealdir);
- }
- #else
- return(NULL);
- #endif /* DTILDE */
- }
-
- /*
- Functions for executing system commands.
- zsyscmd() executes the system command in the normal, default way for
- the system. In UNIX, it does what system() does. Thus, its results
- are always predictable.
- zshcmd() executes the command using the user's preferred shell.
- */
- int
- zsyscmd(s) char *s; {
- #ifdef aegis
- if (!priv_chk()) system(s);
- #else
- #ifdef OS2
- if (!priv_chk()) system(s);
- #else
- PID_T shpid;
- #ifdef COMMENT
- /* This doesn't work... */
- WAIT_T status;
- #else
- int status;
- #endif /* COMMENT */
-
- if (shpid = fork()) {
- if (shpid < (PID_T)0) return(-1); /* Parent */
- while (shpid != (PID_T) wait(&status))
- ;
- return(status);
- }
- if (priv_can()) { /* Child: cancel any priv's */
- printf("?Privilege cancellation failure\n");
- _exit(255);
- }
- execl("/bin/sh","sh","-c",s,NULL);
- perror("/bin/sh");
- _exit(255);
- return(0); /* Shut up ANSI compilers. */
- #endif /* OS2 */
- #endif /* aegis */
- }
-
- /*
- UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
- Adapted to use getpwuid to find login shell because many systems do not
- have SHELL in environment, and to use direct calling of shell rather
- than intermediate system() call. -- H. Fischer
- Call with s pointing to command to execute.
- */
-
- int
- zshcmd(s) char *s; {
- PID_T pid;
-
- #ifdef OS2
- char *shell = getenv("COMSPEC");
- if (!priv_chk())
- if (*s == '\0')
- spawnl(P_WAIT, shell, shell, NULL);
- else
- system(s);
- #else
- #ifdef AMIGA
- if (!priv_chk()) system(s);
- #else
- #ifdef datageneral
- if (priv_chk) return(1);
- if (*s == '\0') /* Interactive shell requested? */
- #ifdef mvux
- system("/bin/sh ");
- #else
- system("x :cli prefix Kermit_Baby:");
- #endif /* mvux */
- else /* Otherwise, */
- system(s); /* Best for aos/vs?? */
-
- #else
- #ifdef aegis
- if ((pid = vfork()) == 0) { /* Make child quickly */
- char *shpath, *shname, *shptr; /* For finding desired shell */
-
- if (priv_can()) exit(1); /* Turn off privs. */
- if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
-
- #else /* All Unix systems */
- if ((pid = fork()) == 0) { /* Make child */
- char *shpath, *shname, *shptr; /* For finding desired shell */
- struct passwd *p;
- char *defshell = "/bin/sh"; /* Default */
-
- if (priv_can()) exit(1); /* Turn off privs. */
- #ifdef COMMENT
- /* Old way always used /etc/passwd shell */
- p = getpwuid(real_uid()); /* Get login data */
- if (p == (struct passwd *) NULL || !*(p->pw_shell))
- shpath = defshell;
- else
- shpath = p->pw_shell;
- #else
- /* New way lets user override with SHELL variable, but does not rely on it. */
- /* This allows user to specify a different shell. */
- shpath = getenv("SHELL"); /* What shell? */
- if (shpath == NULL) {
- p = getpwuid( real_uid() ); /* Get login data */
- if (p == (struct passwd *)NULL || !*(p->pw_shell))
- shpath = defshell;
- else shpath = p->pw_shell;
- }
- #endif /* COMMENT */
- #endif /* aegis */
- shptr = shname = shpath;
- while (*shptr != '\0')
- if (*shptr++ == DIRSEP)
- shname = shptr;
- if (s == NULL || *s == '\0') { /* Interactive shell requested? */
- execl(shpath,shname,"-i",NULL); /* Yes, do that */
- } else { /* Otherwise, */
- execl(shpath,shname,"-c",s,NULL); /* exec the given command */
- } /* If execl() failed, */
- exit(BAD_EXIT); /* return bad return code. */
-
- } else { /* Parent */
-
- int wstat; /* ... must wait for child */
- SIGTYP (*istat)(), (*qstat)();
-
- if (pid == (PID_T) -1) return(0); /* fork() failed? */
-
- istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
- qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
-
- while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
- ; /* Wait for fork */
- signal(SIGINT,istat); /* Restore interrupts */
- signal(SIGQUIT,qstat);
- }
- #endif
- #endif
- #endif
- return(1);
- }
-
- #ifdef aegis
- /*
- Replacement for strchr() and index(), neither of which seem to be universal.
- */
-
- static char *
- #ifdef CK_ANSIC
- xindex(char * s, char c)
- #else
- xindex(s,c) char *s, c;
- #endif /* CK_ANSIC */
- /* xindex */ {
- while (*s != '\0' && *s != c) s++;
- if (*s == c) return(s); else return(NULL);
- }
- #endif /* aegis */
-
- /* I S W I L D -- Check if filespec is "wild" */
-
- /*
- Returns 0 if it is a single file, 1 if it contains wildcard characters.
- Note: must match the algorithm used by match(), hence no [a-z], etc.
- */
- int
- iswild(filespec) char *filespec; {
- char c; int x; char *p;
- if (wildxpand) {
- if ((x = zxpand(filespec)) > 1) return(1);
- if (x == 0) return(0); /* File does not exist */
- p = malloc(MAXNAMLEN + 20);
- znext(p);
- #ifdef OS2
- x = (stricmp(filespec,p) != 0);
- #else
- x = (strcmp(filespec,p) != 0);
- #endif
- free(p);
- return(x);
- } else {
- while ((c = *filespec++) != '\0')
- if (c == '*' || c == '?') return(1);
- return(0);
- }
- }
-
- #ifdef OS2
-
- /* Z C H D S K -- Change currently selected disk device */
-
- /* Returns -1 if error, otherwise 0 */
-
- zchdsk(c) int c; {
- int i = toupper(c) - 64;
- return( _chdrive(i));
- }
-
- #undef stat
- #ifdef __IBMC__STAT
- #define stat(p, s) _stat(p, s)
- #endif /* __IBMC__STAT */
-
- os2stat(char *path, struct stat *st) {
- char local[MAXPATHLEN];
- int len;
-
- strcpy(local, path);
- len = strlen(local);
-
- if ( len == 2 && local[1] == ':' )
- local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
- else if ( len == 0 )
- local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
- else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':' )
- local[len - 1] = 0; /* strip trailing / except after d: */
-
- return stat(local, st);
- }
-
- #endif /* OS2 */
-